home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 10 - 1994 / 10.01 Jan 94 / Programmers' Challenge / ScheduleMatches.c
Encoding:
C/C++ Source or Header  |  1995-07-29  |  5.0 KB  |  265 lines  |  [TEXT/KAHL]

  1. /* ScheduleMatches ----------------------------------------
  2.  *
  3.  * In response to Nov 93 MacTech programmer's challenge.
  4.  *
  5.  * Object is to:
  6.  *    1)     form all combinations of 'numTeams' 'teamNames',
  7.  *        taken two at a time (numTeams even);
  8.  *    2)    match these pairs to 'numTeams'/2
  9.  *        'playingAreaNames';
  10.  *    3)    schedule 'numTeams'/2 "matches" at a time, starting
  11.  *        at 12 noon, with a new set of such matches
  12.  *        scheduled every 15 minutes, until all combinations
  13.  *        are used;
  14.  *    4)    write the whole schedule out to a given ANSI file
  15.  *        stream.
  16.  *
  17.  * Some observations:
  18.  *
  19.  *    number of combinations = C(numTeams,2) =
  20.  *    numTeams*(numTeams-1)/2.
  21.  *    There are then (numTeams-1) sets of matches, or,
  22.  *    times, which must be scheduled.
  23.  *
  24.  * The pairs can be generated geometrically using
  25.  * central cyclical pattern as demonstrated for
  26.  * numTeams = 6:
  27.  *
  28.  *          1           Connecting rods have fixed
  29.  *          |           orientation.  0 stays in center.
  30.  *          |           Other digits cycle clockwise, 
  31.  *    2---\ 0 /---5     or, cc, around circumference.
  32.  *         ---
  33.  *
  34.  *       3-----4
  35.  *
  36.  * Suggested formatting is as follows:
  37.  *
  38.  *    12:xx
  39.  *    areaU: nameJ vs nameK
  40.  *    areaV: nameL vs nameM
  41.  *    .
  42.  *    .
  43.  *    {blank line}
  44.  *    12:xx
  45.  *    .
  46.  *    .
  47.  *
  48.  * billKarsh - solution author.
  49.  *
  50.  */
  51.  
  52. #pragma options( honor_register, !assign_registers )
  53. #pragma options( !check_ptrs )
  54.  
  55. #include    <string.h>
  56. #include    <stdio.h>
  57.  
  58. void ScheduleMatches(
  59.     unsigned short    numTeams,
  60.     Str255            teamNames[],
  61.     Str255            playingAreaNames[],
  62.     FILE            *outputfile );
  63.  
  64. #define        BufSize        1024
  65.  
  66. // BufIt modifier codes
  67. #define        kTime        -1    // write time
  68. #define        kStrn        1    // write string + '\n'
  69. #define        kStrSep        2    // write string + ': '
  70. #define        kStrVs        4    // write string + ' vs '
  71.  
  72. // useful shorthand inside BufIt
  73. // make sure n bytes available in buffer,
  74. // else empty it out
  75.  
  76. #define    BufReady( n )            \
  77.     if( n > b->avail ) {        \
  78.         b->p    = p;            \
  79.         BufFlush();                \
  80.         p        = b->buf;        \
  81.     }
  82.  
  83. typedef struct {
  84.     FILE    *file;    // ANSI stream
  85.     Byte    *buf;    // start of private buffer
  86.     Byte    *p;        // current position in buffer
  87.     short    avail;    // available bytes in buffer
  88.     short    padding;// global data 4-byte aligned
  89. } BufRec;
  90.  
  91. static    BufRec    gBuf;
  92.  
  93.  
  94. /* BufFlush -----------------------------------------------
  95.  *
  96.  * Write current buffer to file.
  97.  */
  98.  
  99. static void BufFlush( void )
  100. {
  101.     register BufRec    *b = &gBuf;
  102.     size_t             n = b->p - b->buf;
  103.     
  104.     if( n ) {
  105.     
  106.         fwrite( b->buf, 1, n, b->file );
  107.             
  108.     // reset buffer
  109.     
  110.         b->p        = b->buf;
  111.         b->avail    = BufSize;
  112.     }
  113. }
  114.  
  115.  
  116. /* BufIt --------------------------------------------------
  117.  *
  118.  * 1) Write string to local buffer if room,
  119.  *        otherwise,
  120.  * 2) Dump buffer to file,
  121.  * 3) resume with step 1.
  122.  *
  123.  * If behavior code, mod, as defined above is >= 0:
  124.  *        data is data starting address,
  125.  *        nBytes of data to write.
  126.  *
  127.  * If mod is special code kTime:
  128.  *        data indexes internal minute string,
  129.  *        nBytes = hour.
  130.  */
  131.  
  132. static void BufIt(
  133.     register Byte    *data,
  134.     register short    nBytes,
  135.     short            mod )
  136. {
  137.     register BufRec    *b        = &gBuf;
  138.     register Byte    *p        = b->p;
  139.     static     Byte    mins[8]    = "00153045";
  140.  
  141.     if( mod < 0 ) {        // write a time
  142.     
  143.         BufReady( 7 );
  144.         
  145.         *p++ = '\n';
  146.         
  147.         // hour
  148.         
  149.         if( !nBytes ) {
  150.             *p++ = '1';
  151.             *p++ = '2';
  152.             b->avail--;
  153.         }
  154.         else
  155.             *p++ = nBytes + '0';
  156.         
  157.         *p++  =':';
  158.         
  159.         // mins
  160.         
  161.         data += (long)mins;
  162.         *p++ = *data++;
  163.         *p++ = *data;
  164.         
  165.         *p++ = '\n';
  166.         b->avail -= 6;
  167.     }
  168.     else {                // write a string
  169.     
  170.         BufReady( nBytes + mod );
  171.         
  172.         memcpy( p, data, nBytes );
  173.         p            += nBytes;
  174.         b->avail    -= nBytes + mod;
  175.         
  176.         switch( mod ) {    // write string suffix
  177.             case kStrn:
  178.                 *p++ = '\n';
  179.                 break;
  180.             case kStrSep:
  181.                 *p++ = ':';
  182.                 *p++ = ' ';
  183.                 break;
  184.             case kStrVs:
  185.                 *p++ = ' ';
  186.                 *p++ = 'v';
  187.                 *p++ = 's';
  188.                 *p++ = ' ';
  189.                 break;
  190.         }
  191.     }
  192.     
  193.     b->p = p;
  194. }
  195.  
  196.  
  197. /* ScheduleMatches ----------------------------------------
  198.  *
  199.  * Driver routine.
  200.  */
  201.  
  202. void ScheduleMatches(
  203.     unsigned short    numTeams,
  204.     Str255            teamNames[],
  205.     Str255            playingAreaNames[],
  206.     FILE            *outputfile )
  207. {
  208.     register Byte    *area, *tmJ, *tmK;
  209.     register short    N    = numTeams,
  210.                     set    = 0, nAreas;
  211.     register long    t1    = (long)*teamNames + 256,
  212.                     tN    = t1 + ((N-2)<<8);
  213.     Byte            localBuf[BufSize];
  214.     
  215.     if( !N || N & 1 ) return;
  216.     
  217. // init local buffer
  218.  
  219.     gBuf.file    = outputfile;
  220.     gBuf.buf    = gBuf.p = localBuf;
  221.     gBuf.avail    = BufSize;
  222.     
  223.     // loop over sets of matches (times)
  224.     
  225.     do {
  226.     
  227.         // do first pair separately, because team[0]
  228.         // is at center, so this pair disjoint from
  229.         // others.
  230.         
  231.         nAreas    = N>>1;
  232.         area    = *playingAreaNames;
  233.         
  234.         BufIt( (Byte*)((set&3)<<1), set>>2, kTime );
  235.         BufIt( area+1, *area, kStrSep );
  236.         
  237.         tmJ = (Byte*)t1 - 256;
  238.         tmK = (Byte*)t1 + (set<<8);
  239.         
  240.         BufIt( tmJ+1, *tmJ, kStrVs );
  241.         BufIt( tmK+1, *tmK, kStrn  );
  242.         
  243.         tmJ = tmK;
  244.         
  245.         // loop over remaining areas (pairs)
  246.         
  247.         while( --nAreas ) {
  248.         
  249.             area += 256;
  250.             BufIt( area+1, *area, kStrSep );
  251.             
  252.             // next pair
  253.             
  254.             tmJ = (long)tmJ < tN ? tmJ+256 : (Byte*)t1;
  255.             tmK = (long)tmK > t1 ? tmK-256 : (Byte*)tN;
  256.             
  257.             BufIt( tmJ+1, *tmJ, kStrVs );
  258.             BufIt( tmK+1, *tmK, kStrn  );
  259.         };
  260.         
  261.     } while( ++set < N - 1 );
  262.     
  263.     BufFlush();
  264. }
  265.